<?php

class Application
{
    /**
     * Route Object
     * @var Route 
     */
    protected $route;
    
    /**
     * Before Dispatch Action List
     * @var array 
     */
    protected $controllerPluginBeforeDispatchList;
    
    /**
     * After Dispatch Action List
     * @var array 
     */
    protected $controllerPluginAfterDispatchList;
    
    public function __construct() {
        $this->route = new Route();
        $this->controllerPluginBeforeDispatchList = array();
        $this->controllerPluginAfterDispatchList = array();
    }
       
    private function dispatch()
    {       
        $controllerFile = 'application/controller/'.$this->route->controller.'Controller.php';
        
        if(file_exists($controllerFile))
        {
            include $controllerFile;
        }
        else 
        {
            throw new Exception ('Arquivo '.$controllerFile. ' não encontrado.');
        }
        
        $controllerClassName =  $this->route->controller.'Controller';
        if (class_exists($controllerClassName))
        {
            $controllerObj = new $controllerClassName;
        }
        else
        {
            throw new Exception(' Class '.$controllerClassName.' não encontrado.');
        }
        
        $actionName = $this->route->action.'Action';
        if (method_exists($controllerObj,$actionName))
        {
            $view = $this->route->controller.'/'.$this->route->action.'.phtml';
            $controllerObj->setView($view);  
            $controllerObj->setParams($this->route->params);
            $controllerObj->$actionName();
        }
        else
        {
            throw new Exception('Action '.$actionName.' não encontrada.');        
        }
    }
    
    public function addControllerPluginBeforeDispatch($class,$method)
    {
        $this->controllerPluginBeforeDispatchList[] = array("class"=>$class, "method"=>$method);
    }
    
    public function addControllerPluginAfterDispatch($class,$method)
    {
        $this->controllerPluginAfterDispatchList[] = array("class"=>$class, "method"=>$method);
    }
    
    public function pluginDispatch($list)
    {
        foreach($list as $item)
        {
            $class = $item['class'];
            $method = $item['method'];
            if (class_exists($class))
            {
                $objPlugin = new $class;
                if (method_exists($objPlugin,$method)){
                    $this->route = $objPlugin->$method($this->route);                    
                }
            }
        }
    }
        
    public function run()
    {
        
        $this->pluginDispatch($this->controllerPluginBeforeDispatchList);
        $this->dispatch();
        $this->pluginDispatch($this->controllerPluginAfterDispatchList);
                
    }    
    
    public static function ErrorHandler($err_severity, $err_msg, $err_file, $err_line)
    {
        $erro = NULL;
        if (0 === error_reporting()) { return false;}
        switch($err_severity)
        {
            case E_ERROR:               $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_WARNING:             $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_PARSE:               $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_NOTICE:              $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_CORE_ERROR:          $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_CORE_WARNING:        $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_COMPILE_ERROR:       $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_COMPILE_WARNING:     $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_ERROR:          $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_WARNING:        $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_NOTICE:         $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_STRICT:              $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_RECOVERABLE_ERROR:   $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_DEPRECATED:          $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
            case E_USER_DEPRECATED:     $erro = new ApplicationException ($err_msg, 0, $err_severity, $err_file, $err_line);
        }
        if(isset($erro))
        {
            $_SESSION['ApplicationError'] = $erro->toCustomMessage($err_severity, $err_msg, $err_file, $err_line);
            self::redirectPage('Error', 'Index');      
        }    
        return true;
    }
    
    
     public static function getLastError()
     {
         $msg = $_SESSION['ApplicationError'];
         $_SESSION['ApplicationError'] = NULL;
         return $msg;
     }
     
    /**
     * Redirect application to route
     * @param Route $route
     */
    public static function redirect($route)
    {
        header("Location: ".$route->getUrl());
        exit;
    }
    
    /**
     * Redirect application to route
     * @param Route $route
     */
    public static function redirectPage($controller,$action,$params = array())
    {
        header("Location: ".Route::Url($controller, $action, $params));
        exit;
    }
}
    

